﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Atmk.WaterMeter.MIS.Commons.Enums;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Logic.Statistics;
using Atmk.WaterMeter.MIS.Commons.Interfaces.Repository;
using Atmk.WaterMeter.MIS.Commons.Utils;
using Atmk.WaterMeter.MIS.Commons.ViewModels.Chart;
using Atmk.WaterMeter.MIS.Entities;
using Atmk.WaterMeter.MIS.Entities.Models;
using NLog;

namespace Atmk.WaterMeter.MIS.Logic.Statistics
{
    public class WaterConsumptionLogic : IWaterConsumptionLogic
    {
        private static readonly Logger _logger = LogManager.GetCurrentClassLogger();
        private readonly IOwnerRepository _ownerRepository;
        private readonly IMeterRepository _meterRepository;
        private readonly IMeterReadingRepository _meterReadingRepository;
        private readonly IDistrictRepository _districtRepository;
        private readonly IStepTariffRepository _stepTariffRepository;

        public WaterConsumptionLogic(
            IOwnerRepository ownerRepository,
            IMeterRepository meterRepository,
            IMeterReadingRepository meterReadingRepository,
            IDistrictRepository districtRepository,
            IStepTariffRepository stepTariffRepository
        )
        {
            _ownerRepository = ownerRepository;
            _meterRepository = meterRepository;
            _meterReadingRepository = meterReadingRepository;
            _districtRepository = districtRepository;
            _stepTariffRepository = stepTariffRepository;
        }

        /// <summary>
        /// 获取指定片区集合下的，当前日期所在的一段时间(按月、季度)内的每月用水总量
        /// </summary>
        /// <param name="period"></param>
        /// <param name="dateTime"></param>
        /// <param name="leafDistrictIds"></param>
        /// <returns></returns>
        public WaterConsumptionsCountData GetDistrictMonthWatherConsumption(Period period, DateTime dateTime,
            params string[] leafDistrictIds)
        {
            //获取片区
            var districts = _districtRepository.GetDistrictsById(leafDistrictIds);

            //获取当前日期所在月首日
            var firstday = new DateTime(dateTime.Year, dateTime.Month, 1);
            var months = 1;
            if (period == Period.Quarter)
            {
                firstday = DateTimeHelper.GetQuarter(dateTime);
                months = 3;
            }

            var r = new WaterConsumptionsCountData
            {
                list = new List<WaterConsumptionsCountListItem>()
            };
            foreach (var item in districts)
            {
                //获取业主
                var owners = _ownerRepository.GetOwners(item.Id.ToString());
                //获取水表
                var meters = _meterRepository.GetMetersByOwnerIds(owners.Select(o => o.Id.ToString()).ToArray());

                var listItem = new WaterConsumptionsCountListItem
                {
                    districtId = item.Id.ToString(),
                    districtName = item.Name,
                    waterConsumptions = new List<double>()
                };
                for (var i = 0; i < months; i++)
                {
                    listItem.waterConsumptions.Add(0);//初始化
                }
                for (var i = 0; i < listItem.waterConsumptions.Count; i++)
                {
                    DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate,
                        firstday.AddMonths(i));
                    var meterReadings =
                        _meterReadingRepository.GetDateMeterReadingRecords(meters.Select(m => m.MeterNumber).ToArray());
                    //按片区统计指定年/季度的每个月的用水量
                    listItem.waterConsumptions[i] = RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate)
                        .Sum(l => l.Last().Value - l.First().Value);
                }
                r.list.Add(listItem);
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        /// <summary>
        /// 获取指定片区集合下的，当前日期所在的一段时间(按月、季度、年)内的阶梯用水总量统计
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="leafDistrictIds"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        public WaterConsumptionsCountData GetDistrictPriceStepWaterConsumption(Period period, DateTime dateTime,
            params string[] leafDistrictIds)
        {
            //获取片区
            var districts = _districtRepository.GetDistrictsById(leafDistrictIds);

            //值字典
            var dictionary = new Dictionary<string, List<double>>();

            foreach (var dis in districts)
            {
                dictionary[dis.Id.ToString()] = new List<double>(3) { 0, 0, 0 };
                //获取业主
                var owners = _ownerRepository.GetOwners(dis.Id.ToString());
                foreach (var owner in owners)
                {
                    var list = GetPriceStepWaterConsumption(period, dateTime, owner.Id.ToString());
                    for (var i = 0; i < dictionary[dis.Id.ToString()].Count; i++)
                    {
                        dictionary[dis.Id.ToString()][i] += list[i];
                    }

                }
            }
            //获取每户的阶梯用水量，然后按片区分组相加
            var result = new WaterConsumptionsCountData
            {
                list = districts.Select(d => new WaterConsumptionsCountListItem
                {
                    districtId = d.Id.ToString(),
                    districtName = d.Name,
                    waterConsumptions = dictionary[d.Id.ToString()]
                }).ToList(),
                total = districts.Count.ToString()
            };
            return result;
        }


        /// <summary>
        /// 获取指定片区集合下的，当前日期所在的一段时间(按月、季度、年)内的业主阶梯用水总量统计
        /// </summary>
        /// <param name="period"></param>
        /// <param name="dateTime"></param>
        /// <param name="ownerId"></param>
        /// <returns></returns>
        public List<double> GetPriceStepWaterConsumption(Period period, DateTime dateTime, string ownerId)
        {
            DateTimeHelper.GetPeriod(period, out var beginDate, out var endDate, dateTime);
            //用量倍数参数
            var multi = GetMultiplicand(period);
            //获取该户所有水表号
            var meters = _meterRepository.GetMetersByOwnerIds(ownerId);
            //获取水表的抄表记录
            var records = _meterReadingRepository.GetDateMeterReadingRecords(meters.Select(m => m.MeterNumber).ToArray());
            var list = RangeMeterReadingRecord(records, beginDate, endDate);
            //获取不同水表用水总量
            var meterDic = new Dictionary<string, double>();
            foreach (var item in list)
            {
                meterDic[item.First().CtdeviceId] = item.Last().Value - item.First().Value;
            }
            //获取不同水表阶梯水价
            var piceStep = _stepTariffRepository.GetMeterNumberPriceStep(meters.ToArray());

            //按不同水表用水量合并
            var result = new List<double>(3) { 0, 0, 0 };
            foreach (var dic in meterDic)
            {
                var res = GetStepConsumption(piceStep[dic.Key], dic.Value, multi);
                for (var i = 0; i < result.Count; i++)
                {
                    result[i] += res[i];
                }
            }
            return result;
        }

        private List<double> GetStepConsumption(PrcieStep PrcieStep, double value, int multi)
        {
            var point1 = PrcieStep.CutPoint1 * multi;
            var point2 = PrcieStep.CutPoint2 * multi;
            double step2 = 0;
            double step3 = 0;
            double step1 = value;
            if (value - point1 > 0)
            {
                step1 = point1;
                step2 = value - point1;
                if (step2 - (point2 - point1) > 0)
                {
                    step2 = point2 - point1;
                    if (value - point2 > 0)
                    {
                        step3 = value - point2;
                    }
                }
            }
            var result = new List<double> { step1, step2, step3 };

            return result;
        }

        private int GetMultiplicand(Period period)
        {
            switch (period)
            {
                case Period.Month: return 1;
                case Period.Quarter: return 3;
                case Period.Year: return 12;
            }
            return 1;
        }

        /// <summary>
        /// 获取指定片区集合下的，当前日期所在的一段时间(按日、月、季度、年)内的各用户用水总量
        /// </summary>
        public YesterdayConsumptionData GetWaterConsumption(Period period, DateTime dateTime, params string[] leafDistrictIds)
        {
            DateTimeHelper.GetPeriod(period, out var beginDate, out var endDate, dateTime);
            //获取片区
            var districts = _districtRepository.GetDistrictsById(leafDistrictIds);
            var r = new YesterdayConsumptionData
            {
                list = new List<YesterdayConsumptionListItem>()
            };
            foreach (var item in districts)
            {
                //获取业主
                var owners = _ownerRepository.GetOwners(item.Id.ToString());
                foreach (var ow in owners)
                {
                    //获取水表
                    var meters = _meterRepository.GetMetersByOwnerIds(ow.Id.ToString());
                    var meterReadings =
                        _meterReadingRepository.GetDateMeterReadingRecords(meters.Select(m => m.MeterNumber).ToArray());
                    var tempwaterConsumption = RangeMeterReadingRecord(meterReadings, beginDate, endDate)
                        .Sum(l => l.Last().Value - l.First().Value);
                    var listitem = new YesterdayConsumptionListItem
                    {
                        ownerId = ow.Id.ToString(),
                        houseNumber = ow.HouseNumber,
                        waterConsumption = tempwaterConsumption
                    };
                    r.list.Add(listitem);
                }
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        /// <summary>
        /// 获取指定片区集合下的总用水量统计
        /// </summary>
        /// <param name="leafDistrictIds"></param>
        /// <returns></returns>
        public WaterConsumptionInfoData GetWaterConsumptionInfoData(params string[] leafDistrictIds)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 获取指定片区集合下的，当前日期所在的一段时间(年)内的每月用水总量
        /// </summary>
        /// <param name="period"></param>
        /// <param name="dateTime"></param>
        /// <param name="leafDistrictIds"></param>
        /// <returns></returns>
        public YearWaterConsumptionsCountData GetYearWaterConsumptions(Period period, DateTime dateTime,
            params string[] leafDistrictIds)
        {
            //获取片区
            var districts = _districtRepository.GetDistrictsById(leafDistrictIds);
            var dt = new DateTime(dateTime.Year, 1, 1);
            var r = new YearWaterConsumptionsCountData
            {
                list = new List<WaterConsumptionsCountListItem>()
            };
            foreach (var item in districts)
            {  //获取业主
                var owners = _ownerRepository.GetOwners(item.Id.ToString());
                //获取所有水表
                var meters = _meterRepository.GetMetersByOwnerIds(owners.Select(o => o.Id.ToString()).ToArray());
                var listItem = new WaterConsumptionsCountListItem
                {
                    districtId = item.Id.ToString(),
                    districtName = item.Name,
                    waterConsumptions = new List<double>()
                };
                for (var i = 0; i < 12; i++)
                {
                    listItem.waterConsumptions.Add(0);
                }
                for (var i = 0; i < listItem.waterConsumptions.Count; i++)
                {
                    DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate,
                        dt.AddMonths(i));
                    var meterReadings =
                        _meterReadingRepository.GetDateMeterReadingRecords(meters.Select(m => m.MeterNumber).ToArray());
                    //按片区统计指定年的每个月的用水量
                    listItem.waterConsumptions[i] = RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate)
                        .Sum(l => l.Last().Value - l.First().Value);
                }
                r.list.Add(listItem);
            }
            r.total = r.list.Count.ToString();
            return r;
        }

        public WaterConsumptionInfoData GetWaterConsumptionInfoData(string areaId)
        {
            try
            {
                //获取片区
                var districts = _districtRepository.GetLeafDistrictEntities(areaId).ToList();
                //获取业主
                var owners = _ownerRepository.GetOwners(districts.Select(d => d.Id.ToString()).ToArray());
                //获取所有水表
                var meters = _meterRepository.GetMetersByOwnerIds(owners.Select(o => o.Id.ToString()).ToArray());
                //获取抄表数据
                var meterReadings =
                    _meterReadingRepository.GetDateMeterReadingRecords(meters.Select(m => m.MeterNumber).ToArray());
                //获取个水表的
                //获取昨日用水量
                var lastDay = RangeMeterReadingRecord(meterReadings, DateTime.Now.Date.AddDays(-1),
                    DateTime.Now.Date.AddMilliseconds(-1)).Sum(l => l.Last().Value - l.First().Value);
                //本月用水量
                DateTimeHelper.GetPeriod(Period.Month, out var mBegin, out var mEnd);
                var thisMonth = RangeMeterReadingRecord(meterReadings, mBegin, DateTime.Now.Date.AddMilliseconds(-1))
                    .Sum(l => l.Last().Value - l.First().Value);

                //上月用水量记录
                DateTimeHelper.GetPeriod(Period.Month, out var mBeginDate, out var mEndDate, DateTime.Now.AddMonths(-1));
                var lastMonth = RangeMeterReadingRecord(meterReadings, mBeginDate, mEndDate)
                    .Sum(l => l.Last().Value - l.First().Value);
                //同期月用水量//TODO:如何获取暂无概念
                var r = new WaterConsumptionInfoData
                {
                    yesterday = (int)lastDay,
                    nowMonth = (int)thisMonth,
                    lastMonth = (int)lastMonth,
                    sameMonth = 0
                };
                return r;
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// 获取一定时间范围内各,水表集合里的最早抄表记录和最后抄表记录
        /// </summary>
        /// <param name="records"></param>
        /// <param name="sDateTime"></param>
        /// <param name="eDateTime"></param>
        /// <returns></returns>
        private List<List<MeterReadingRecord>> RangeMeterReadingRecord(List<MeterReadingRecord> records,
            DateTime sDateTime, DateTime eDateTime)
        {
            //获取指定时间范围内的抄表记录:大于开始时间小于结束时间
            var baseList = records
                .Where(m => m.ReadTime >= sDateTime && m.ReadTime <= eDateTime)
                .OrderBy(r => r.CtdeviceId).ThenBy(r => r.ReadTime)
                .GroupBy(r => r.CtdeviceId).ToList();
            //获取离开始时间最近的抄表记录
            var starList = baseList.Select(v => v.First());
            //获取离结束时间最近的抄表记录
            var endList = baseList.Select(v => v.Last());
            var result = starList.Select(s => new List<MeterReadingRecord>
            {
                s,
                endList.First(e => e.CtdeviceId == s.CtdeviceId)
            }).ToList();
            return result;
        }

    }
}